package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.heima.article.dto.ArticleStreamMessage;
import com.heima.article.entity.ApArticle;
import com.heima.article.service.IApArticleService;
import com.heima.article.service.IHotArticleService;
import com.heima.common.util.RedisConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.List;

@Service
public class IHotArticleServiceImpl implements IHotArticleService {
    @Autowired
    private IApArticleService articleService;
    @Autowired
    private StringRedisTemplate redisTemplate;


    @Override
    public void compute() {
        LocalDateTime nowTime = LocalDateTime.now();
        LocalDateTime toTime = LocalDateTime.of(nowTime.getYear(), nowTime.getMonth(), nowTime.getDayOfMonth(), 0, 0);
        LocalDateTime fromTime = LocalDateTime.of(nowTime.getYear(), nowTime.getMonth(), nowTime.getDayOfMonth()-5, 0, 0);
        Date now = new Date();
        Date to = new Date(now.getYear(), now.getMonth(), now.getDate());
        // 往前推5天
        Date from = new Date(to.getTime() - 5 * 24 * 60 * 60 * 1000);
        // 存文章的JSON数据,主要存页面展示的数据 要保存的是不变的数据
        LambdaQueryWrapper<ApArticle> query = new LambdaQueryWrapper<>();
        query.ge(ApArticle::getPublishTime,new Date(fromTime.toInstant(ZoneOffset.of("+8")).toEpochMilli()));
        query.le(ApArticle::getPublishTime, new Date(toTime.toInstant(ZoneOffset.of("+8")).toEpochMilli()));
       /* query.ge(ApArticle::getPublishTime, from);
        query.lt(ApArticle::getPublishTime, to);*/
        // 过滤已删除已下架的文章
        query.eq(ApArticle::getIsDown, false);
        query.eq(ApArticle::getIsDelete, false);
        List<ApArticle> articles = articleService.list(query);
        for (ApArticle article : articles) {
            double score=computeScore(article);
            ApArticle toCache = new ApArticle();
            toCache.setId(article.getId());
            toCache.setTitle(article.getTitle());
            toCache.setAuthorId(article.getAuthorId());
            toCache.setAuthorName(article.getAuthorName());
            toCache.setChannelId(article.getChannelId());
            toCache.setChannelName(article.getChannelName());
            toCache.setPublishTime(article.getPublishTime());
            toCache.setCreatedTime(article.getCreatedTime());
            toCache.setStaticUrl(article.getStaticUrl());
            toCache.setImages(article.getImages());
            toCache.setLayout(article.getLayout());
            String value = JSON.toJSONString(toCache);
            // 使用zset数据结构来保存
            redisTemplate.opsForZSet().add(RedisConstant.HOT_ARTICLE, value, score);
        }


    }


        @Override
        public void update(ArticleStreamMessage message) {
            // 根据文章id查询文章
            ApArticle article = articleService.getById(message.getArticleId());
            // 计算文章的本次聚合的操作分值
            double scorePlus = computeScore(message);
            // 判断当前的文章数据是否已经缓存在redis中

            // 将文章不变的字段保存(页面需要的字段)
            ApArticle articleToCache = new ApArticle();
            articleToCache.setId(article.getId());
            articleToCache.setTitle(article.getTitle());
            articleToCache.setAuthorId(article.getAuthorId());
            articleToCache.setAuthorName(article.getAuthorName());
            articleToCache.setImages(article.getImages());
            articleToCache.setChannelId(article.getChannelId());
            articleToCache.setChannelName(article.getChannelName());
            articleToCache.setPublishTime(article.getPublishTime());

            String firstKey = "hot_article_first_page_0";
            String json = JSON.toJSONString(articleToCache);

            Double score = redisTemplate.opsForZSet().score(firstKey, json);
            if (score != null) {
                // 如果已经换成在redis中,在redis中加上增量的分值
                redisTemplate.opsForZSet().incrementScore(firstKey, json, scorePlus);
            } else {
                // 如果不在redis中,需要先计算之前的分值,再加上增量的分值,再添加数据到redis中
                double scorePre = computeScore(article);
                double scoreFinal = scorePre + scorePlus;
                redisTemplate.opsForZSet().add(firstKey, json, scoreFinal);
            }

            String channelKey = "hot_article_first_page_" + article.getChannelId();
            Double scoreChannel = redisTemplate.opsForZSet().score(channelKey, json);
            if (scoreChannel != null) {
                // 如果已经换成在redis中,在redis中加上增量的分值
                redisTemplate.opsForZSet().incrementScore(channelKey, json, scorePlus);
            } else {
                // 如果不在redis中,需要先计算之前的分值,再加上增量的分值,再添加数据到redis中
                double scorePre = computeScore(article);
                double scoreFinal = scorePre + scorePlus;
                redisTemplate.opsForZSet().add(channelKey, json, scoreFinal);
            }

            // 需要将本次聚合操作的数据写入到文章表中
            LambdaUpdateWrapper<ApArticle> update = new LambdaUpdateWrapper<>();
            // 在MySQL中,一条sql语句本身就是一个事务
            // update ap_article set views = views + 1,likes = likes + 1,comment = comment + 1,collection = collection + 1 where id = ?
            update.eq(ApArticle::getId, message.getArticleId());
            update.setSql("views = views + " + message.getView());
            update.setSql("likes = likes + " + message.getLike());
            update.setSql("comment = comment + " + message.getComment());
            update.setSql("collection = collection + " + message.getCollect());

            // 100 用户点赞  原来的数量为0
            // article.setViews(article.getViews()+(int)message.getView());

            articleService.update(update);

        }

        /**
         * 计算增量分值
         *
         * @param message
         * @return
         */
        private double computeScore(ArticleStreamMessage message) {
            double score = 0;
            score += message.getView() * 1 * 3;
            score += message.getLike() * 3 * 3;
            score += message.getComment() * 5 * 3;
            score += message.getCollect() * 8 * 3;
            return score;
        }


    private double computeScore(ApArticle article) {
        // 阅读权重 1
        // 点赞权重 3
        // 评论权重 5
        // 收藏权重 8
        double score = 0;
        if (article.getViews() != null) {
            score += 1 * article.getViews();
        }
        if (article.getLikes() != null) {
            score += 3 * article.getLikes();
        }
        if (article.getComment() != null) {
            score += 5 * article.getComment();
        }
        if (article.getCollection() != null) {
            score += 8 * article.getCollection();
        }
        return score;
    }
}
